﻿using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;

namespace Geeno.Common
{
    /// <summary>
    /// XML的基本操作，注意使用的框架版本会影响一些写法
    /// </summary>
    public class XmlUtil
    {
        public static string XmlSerialize<T>(T obj)
        {
            //针对输出的XML格式处理
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Encoding = Encoding.UTF8;
            settings.Indent = true; //是否自动缩进
            string xmlString = string.Empty;

            var xmlSerializer = new XmlSerializer(typeof(T));
            using (MemoryStream ms = new MemoryStream())
            {
                XmlWriter writer = XmlWriter.Create(ms, settings);
                xmlSerializer.Serialize(writer, obj);
                xmlString = Encoding.UTF8.GetString(ms.ToArray());
            }
            return xmlString;
        }
        /*
        XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
		namespaces.Add("ceb", "http://www.chinaport.gov.cn/ceb");
		namespaces.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance");
        注意对应的类名上需要包含[XmlRoot(Namespace = "http://www.chinaport.gov.cn/ceb")]
         */
        /// <summary>
        /// 指定命名空间进行序列化
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="namespaces"></param>
        /// <returns></returns>
        public static string XmlSerialize<T>(T obj, XmlSerializerNamespaces namespaces)
        {
            //针对输出的XML格式处理
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Encoding = Encoding.UTF8;
            settings.Indent= true;
            string xmlString = string.Empty;

            var xmlSerializer = new XmlSerializer(typeof(T));
            using (MemoryStream ms = new MemoryStream())
            {
                XmlWriter writer = XmlWriter.Create(ms, settings);
                xmlSerializer.Serialize(writer, obj, namespaces);
                xmlString = Encoding.UTF8.GetString(ms.ToArray());
            }
            return xmlString;
        }
        /// <summary>
        /// 按指定root标签返回包含声明不包含命名空间的XML
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="rootName"></param>
        /// <returns></returns>
        public static string XmlSerialize<T>(T obj, string rootName)
        {
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Encoding = Encoding.UTF8;
            var serializer = new XmlSerializer(obj.GetType(), new XmlRootAttribute(rootName));
            var stream = new MemoryStream();
            var xmlString = string.Empty;
            using (XmlWriter xmlWriter = XmlWriter.Create(stream, settings))
            {
                XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
                namespaces.Add(string.Empty, string.Empty);
                serializer.Serialize(xmlWriter, obj, namespaces);
                xmlString = Encoding.UTF8.GetString(stream.ToArray());
            };
            return xmlString;
        }
        /// <summary>
        /// XML String 反序列化成对象
        /// </summary>
        public static T XmlDeserialize<T>(string xmlString)
        {
            T t = default(T);
            if (xmlString != null && !xmlString.Equals(""))
            {
                XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
                using (Stream xmlStream = new MemoryStream(Encoding.UTF8.GetBytes(xmlString)))
                {
                    using (XmlReader xmlReader = XmlReader.Create(xmlStream))
                    {
                        Object obj = xmlSerializer.Deserialize(xmlReader);
                        t = (T)obj;
                    }
                }
            }
            return t;
        }
        /// <summary>
        /// XML String 反序列化成对象,指定rootName
        /// </summary>
        public static T XmlDeserialize<T>(string xmlString, string rootName)
        {
            T t = default(T);
            if (xmlString != null && !xmlString.Equals(""))
            {
                XmlSerializer xmlSerializer = new XmlSerializer(typeof(T), new XmlRootAttribute(rootName));
                using (Stream xmlStream = new MemoryStream(Encoding.UTF8.GetBytes(xmlString)))
                {
                    using (XmlReader xmlReader = XmlReader.Create(xmlStream))
                    {
                        Object obj = xmlSerializer.Deserialize(xmlReader);
                        t = (T)obj;
                    }
                }
            }
            return t;
        }


        public static T XmlToModel<T>(string xml)
        {
            xml = Regex.Replace(xml, @"<\?xml*.*?>", "", RegexOptions.IgnoreCase);
            XmlSerializer xmlSer = new XmlSerializer(typeof(T));
            using (StringReader xmlReader = new StringReader(xml))
            {
                return (T)xmlSer.Deserialize(xmlReader);
            }
        }
        /// <summary>
        /// 将一个对象序列化为XML字符串
        /// </summary>
        /// <param name="o">要序列化的对象</param>
        /// <param name="encoding">编码方式</param>
        /// <returns>序列化产生的XML字符串</returns>
        public static string XmlSerializeWeb(object o, Encoding encoding)
        {
            if (o == null)
                throw new ArgumentNullException("o");
            if (encoding == null)
                throw new ArgumentNullException("encoding");

            string xml = "";
            try
            {
                using (MemoryStream stream = new MemoryStream())
                {
                    XmlWriterSettings settings = new XmlWriterSettings();
                    settings.Encoding = encoding;

                    //OmitXmlDeclaration表示不生成声明头，默认是false，OmitXmlDeclaration为true，会去掉<?xml version="1.0" encoding="UTF-8"?>
                    //settings.OmitXmlDeclaration = true;

                    XmlWriter writer = XmlWriter.Create(stream, settings);

                    //强制指定命名空间，覆盖默认的命名空间，可以添加多个，如果要在xml节点上添加指定的前缀，可以在跟节点的类上面添加[XmlRoot(Namespace = "http://www.w3.org/2001/XMLSchema-instance", IsNullable = false)]，Namespace指定哪个值，xml节点添加的前缀就是哪个命名空间(这里会添加ceb)

                    XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
                    namespaces.Add("ceb", "http://www.chinaport.gov.cn/ceb");
                    namespaces.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance");
                    namespaces.Add("ds", "http://www.w3.org/2000/09/xmldsig#");

                    XmlSerializer serializer = new XmlSerializer(o.GetType());
                    serializer.Serialize(writer, o, namespaces);
                    writer.Close();

                    stream.Position = 0;
                    using (StreamReader reader = new StreamReader(stream, encoding))
                    {
                        xml = reader.ReadToEnd();
                    }
                }
            }
            catch (Exception ex)
            {

            }
            return xml;
        }
    }

    public class LinqToXMLHelper
    {
        /// <summary>
        /// 1. 下面实例主要针对有命名空间限制的节点的读取，所以读取含指定命名空间的节点的话，
        /// 需要加上命名空间进行读取。
        /// 2. 如果内嵌的节点还有其他的命名空间进行限制的话， 那么读取这个节点就必须采用内嵌的命名空间进行读取。
        /// </summary>
        /// <returns></returns>
        public string RebuildXML()
        {
            var xmlDoc = XDocument.Load(AppDomain.CurrentDomain.BaseDirectory + @"\DHLRequest.xml");
            XNamespace envelope = "http://schemas.xmlsoap.org/soap/envelope/";
            XNamespace cisbase = "http://dhl.de/webservice/cisbase";
            XNamespace bus = "http://dhl.de/webservices/businesscustomershipping";
            var root = xmlDoc.Element(envelope + "Envelope");
            //<cis:Authentification>
            var cisTag = root.Element(envelope + "Header").Element(cisbase + "Authentification");
            var cisUser = cisTag.Element(cisbase + "user");
            var cisSignature = cisTag.Element(cisbase + "signature");
            cisUser.Value = "";
            cisSignature.Value = "";
            //shipment--这个就是多命名空间进行读取节点的操作
            var shipmentTag = root.Element(envelope + "Body")
                .Element(bus + "CreateShipmentOrderRequest")
                .Element("ShipmentOrder").Element("Shipment");
            //ShipmentDetails
            var shipMentDetailsTag = shipmentTag.Element("ShipmentDetails");
            var accountNumber = shipMentDetailsTag.Element(cisbase + "accountNumber");
            accountNumber.Value = "";//节点读取后，进行赋值操作
            return xmlDoc.ToString();//将更改后的数据节点信息--转化成xml字符串结果。
        }

        /// <summary>
        /// 通过Xelement对象，进行构造包括指定命名空间的元素
        /// 返回xml内容的字符串
        /// </summary>
        /// <returns></returns>
        private void BuildXMLByElement()
        {
            var xdoc = new XDocument();
            //定义命名空间
            XNamespace soapenv = "http://schemas.xmlsoap.org/soap/envelope/";
            XNamespace cis = "http://dhl.de/webservice/cisbase";
            XNamespace bus = "http://dhl.de/webservices/businesscustomershipping";
            //声明根元素
            var Envelope = new XElement(soapenv.GetName("Envelope"),
                    new XAttribute(XNamespace.Xmlns + "soapenv", soapenv)
                    , new XAttribute(XNamespace.Xmlns + "cis", cis)
                    , new XAttribute(XNamespace.Xmlns + "bus", bus));
            //HeaderTree
            var headerTree = new XElement(soapenv.GetName("Header"),
                new XElement(cis.GetName("Authentification"),
                    new XElement(cis.GetName("user"), "zebrapreim"),//--value
                    new XElement(cis.GetName("signature"), "YAQ!2wsxYAQ!2wsx")));//--value

            var bodyTree = new XElement(soapenv.GetName("Body"),
                new XElement(cis.GetName("Authentification"),
                    new XElement(cis.GetName("user"), "zebrapreim"),//--value
                    new XElement(cis.GetName("signature"), "YAQ!2wsxYAQ!2wsx")));//--value
            Envelope.Add(headerTree);
            Envelope.Add(bodyTree);
            xdoc.Add(Envelope);
            xdoc.Save("test.xml");
        }
    }
}



/*
关于XMLserilazer的特殊说明：对于XMLSerilazer而言，
只要一 Specified后缀进行修饰的成员，他们会控制可选
valueType成员的序列化，并且这个修饰字段的类型必须是bool
private string userNameField;
private bool userNameFieldSpecified;
        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string UserName
        {
            get
            {
                return this.userNameField;
            }
            set
            {
                this.userNameField = value;
            }
        }
        [System.Xml.Serialization.XmlIgnoreAttribute()]
        public bool UserNameSpecified
        {
            get
            {
                return this.userNameFieldSpecified;
            }
            set
            {
                this.userNameFieldSpecified = value;
            }
        }
		
		
		-->1. 正常进行序列化的话就需要： 
		 var person = new Person()
            {
                UserName = "Jack",
                UserNameSpecified = true,
                
            };
			-->设置成true,不然的话就不会进行序列化的操作
*/
